ExtractFramesFromMovie
Demo macro to extract frames and get frame means from an avi movie and save individual frames to separate image files.Then rebuilds a new movie by recalling the saved images from disk. Also computes the mean gray value of the color channels and detects the difference between a frame and the previous frame. % Demo macro to extract frames and get frame means from an avi movie % and save individual frames to separate image files. % Then rebuilds a new movie by recalling the saved images from disk. % Also computes the mean gray value of the color channels % And detects the difference between a frame and the previous frame. clc; % Clear the command window. close all; % Close all figures (except those of imtool.) imtool close all; % Close all imtool figures. clear; % Erase all existing variables. workspace; % Make sure the workspace panel is showing. fontSize = 14; % Change the current folder to the folder of this m-file. % (The line of code below is from Brett Shoelson of The Mathworks.) if(~isdeployed) cd(fileparts(which(mfilename))); end % Open the rhino.avi demo movie that ships with MATLAB. folder = fullfile(matlabroot, '\toolbox\images\imdemos'); movieFullFileName = fullfile(folder, 'rhinos.avi'); % Check to see that it exists. if ~exist(movieFullFileName, 'file') strErrorMessage = sprintf('File not found:\n%s\nYou can choose a new one, or cancel', movieFullFileName); response = questdlg(strErrorMessage, 'File not found', 'OK - choose a new movie.', 'Cancel', 'OK - choose a new movie.'); if strcmpi(response, 'OK - choose a new movie.') folderName, FilterIndex = uigetfile('*.avi'); if ~isequal(baseFileName, 0) movieFullFileName = fullfile(folderName, baseFileName); else return; end else return; end end try videoObject = VideoReader(movieFullFileName) % Determine how many frames there are. numberOfFrames = videoObject.NumberOfFrames; vidHeight = videoObject.Height; vidWidth = videoObject.Width; numberOfFramesWritten = 0; % Prepare a figure to show the images in the upper half of the screen. figure; % screenSize = get(0, 'ScreenSize'); % Enlarge figure to full screen. set(gcf, 'units','normalized','outerposition',0 1 1); % Ask user if they want to write the individual frames out to disk. promptMessage = sprintf('Do you want to save the individual frames out to individual disk files?'); button = questdlg(promptMessage, 'Save individual frames?', 'Yes', 'No', 'Yes'); if strcmp(button, 'Yes') writeToDisk = true; % Extract out the various parts of the filename. baseFileName, extentions = fileparts(movieFullFileName); % Make up a special new output subfolder for all the separate % movie frames that we're going to extract and save to disk. % (Don't worry - windows can handle forward slashes in the folder name.) folder = pwd; % Make it a subfolder of the folder where this m-file lives. outputFolder = sprintf('%s/Movie Frames from %s', folder, baseFileName); % Create the folder if it doesn't exist already. if ~exist(outputFolder, 'dir') mkdir(outputFolder); end else writeToDisk = false; end % Loop through the movie, writing all frames out. % Each frame will be in a separate file with unique name. meanGrayLevels = zeros(numberOfFrames, 1); meanRedLevels = zeros(numberOfFrames, 1); meanGreenLevels = zeros(numberOfFrames, 1); meanBlueLevels = zeros(numberOfFrames, 1); for frame = 1 : numberOfFrames % Extract the frame from the movie structure. thisFrame = read(videoObject, frame); % Display it hImage = subplot(2, 2, 1); image(thisFrame); caption = sprintf('Frame %4d of %d.', frame, numberOfFrames); title(caption, 'FontSize', fontSize); drawnow; % Force it to refresh the window. % Write the image array to the output file, if requested. if writeToDisk % Construct an output image file name. outputBaseFileName = sprintf('Frame %4.4d.png', frame); outputFullFileName = fullfile(outputFolder, outputBaseFileName); % Stamp the name and frame number onto the image. % At this point it's just going into the overlay, % not actually getting written into the pixel values. text(5, 15, outputBaseFileName, 'FontSize', 20); % Extract the image with the text "burned into" it. frameWithText = getframe(gca); % frameWithText.cdata is the image with the text % actually written into the pixel values. % Write it out to disk. imwrite(frameWithText.cdata, outputFullFileName, 'png'); end % Calculate the mean gray level. grayImage = rgb2gray(thisFrame); meanGrayLevels(frame) = mean(grayImage(:)); % Calculate the mean R, G, and B levels. meanRedLevels(frame) = mean(mean(thisFrame(:, :, 1))); meanGreenLevels(frame) = mean(mean(thisFrame(:, :, 2))); meanBlueLevels(frame) = mean(mean(thisFrame(:, :, 3))); % Plot the mean gray levels. hPlot = subplot(2, 2, 2); hold off; plot(meanGrayLevels, 'k-', 'LineWidth', 2); hold on; plot(meanRedLevels, 'r-'); plot(meanGreenLevels, 'g-'); plot(meanBlueLevels, 'b-'); grid on; % Put title back because plot() erases the existing title. title('Mean Gray Levels', 'FontSize', fontSize); if frame 1 xlabel('Frame Number'); ylabel('Gray Level'); % Get size data later for preallocation if we read % the movie back in from disk. columns, numberOfColorChannels = size(thisFrame); end % Update user with the progress. Display in the command window. if writeToDisk progressIndication = sprintf('Wrote frame %4d of %d.', frame, numberOfFrames); else progressIndication = sprintf('Processed frame %4d of %d.', frame, numberOfFrames); end disp(progressIndication); % Increment frame count (should eventually = numberOfFrames % unless an error happens). numberOfFramesWritten = numberOfFramesWritten + 1; % Now let's do the differencing alpha = 0.5; if frame 1 Background = thisFrame; else % Change background slightly at each frame % Background(t+1)=(1-alpha)*I+alpha*Background Background = (1-alpha)* thisFrame + alpha * Background; end % Display the changing/adapting background. subplot(2, 2, 3); imshow(Background); title('Adaptive Background', 'FontSize', fontSize); % Calculate a difference between this frame and the background. differenceImage = thisFrame - uint8(Background); % Threshold with Otsu method. grayImage = rgb2gray(differenceImage); % Convert to gray level thresholdLevel = graythresh(grayImage); % Get threshold. binaryImage = im2bw( grayImage, thresholdLevel); % Do the binarization % Plot the binary image. subplot(2, 2, 4); imshow(binaryImage); title('Binarized Difference Image', 'FontSize', fontSize); end % Alert user that we're done. if writeToDisk finishedMessage = sprintf('Done! It wrote %d frames to folder\n"%s"', numberOfFramesWritten, outputFolder); else finishedMessage = sprintf('Done! It processed %d frames of\n"%s"', numberOfFramesWritten, movieFullFileName); end disp(finishedMessage); % Write to command window. uiwait(msgbox(finishedMessage)); % Also pop up a message box. % Exit if they didn't write any individual frames out to disk. if ~writeToDisk return; end % Ask user if they want to read the individual frames from the disk, % that they just wrote out, back into a movie and display it. promptMessage = sprintf('Do you want to recall the individual frames\nback from disk into a movie?\n(This will take several seconds.)'); button = questdlg(promptMessage, 'Recall Movie?', 'Yes', 'No', 'Yes'); if strcmp(button, 'No') return; end % Read the frames back in from disk, and convert them to a movie. % Preallocate recalledMovie, which will be an array of structures. % First get a cell array with all the frames. allTheFrames = cell(numberOfFrames,1); allTheFrames(:) = {zeros(vidHeight, vidWidth, 3, 'uint8')}; % Next get a cell array with all the colormaps. allTheColorMaps = cell(numberOfFrames,1); allTheColorMaps(:) = {zeros(256, 3)}; % Now combine these to make the array of structures. recalledMovie = struct('cdata', allTheFrames, 'colormap', allTheColorMaps) for frame = 1 : numberOfFrames % Construct an output image file name. outputBaseFileName = sprintf('Frame %4.4d.png', frame); outputFullFileName = fullfile(outputFolder, outputBaseFileName); % Read the image in from disk. thisFrame = imread(outputFullFileName); % Convert the image into a "movie frame" structure. recalledMovie(frame) = im2frame(thisFrame); end % Get rid of old image and plot. delete(hImage); delete(hPlot); % Create new axes for our movie. subplot(1, 3, 2); axis off; % Turn off axes numbers. title('Movie recalled from disk', 'FontSize', fontSize); % Play the movie in the axes. movie(recalledMovie); % Note: if you want to display graphics or text in the overlay % as the movie plays back then you need to do it like I did at first % (at the top of this file where you extract and imshow a frame at a time.) msgbox('Done with this demo!'); catch ME % Some error happened if you get here. strErrorMessage = sprintf('Error extracting movie frames from:\n\n%s\n\nError: %s\n\n)', movieFullFileName, ME.message); uiwait(msgbox(strErrorMessage)); end